package ch4.DataBasedSeparation;

import java.io.Closeable;
import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * 下载缓冲区实现类
 * 每一个线程都有一个对应的下载缓冲区，在该缓冲区中存储着该线程下载的数据，以及该数据在原始文件中的位置
 */

public class DownLoadBuffer implements Closeable {
    /**
     * 当前Buffer中缓冲区的数据相对于整个存储文件的位置偏移
     * 有了globalOffset，就能把多个线程分别下载的数据按照原始顺序拼成完整的文件了
     */
    private long globalOffset;
    /**
     * globalOffset再加上当前这一块数据的上边界，就能卡出来这块数据的起止范围了
     */
    private long upperBound;
    private int offset = 0;
    public final ByteBuffer byteBuf;
    private final Storage storage;

    public DownLoadBuffer(long globalOffset, long upperBound, final Storage storage) {
        this.globalOffset = globalOffset;
        this.upperBound = upperBound;
        this.byteBuf = ByteBuffer.allocate(1024 * 1024);
        this.storage = storage;
    }

    public void write(ByteBuffer buf) throws IOException {
        int length = buf.position();
        final int capacity = byteBuf.capacity();
        // 如果缓冲区已满，或者剩余容量不够容纳新数据
        if ((offset + length) > capacity || length == capacity) {
            // 将缓冲区中的数据写入文件
            flush();
        }
        byteBuf.position(offset);
        buf.flip();
        byteBuf.put(buf);
        offset += length;
    }

    private void flush() throws IOException {
        int length;
        // flip函数，将缓冲区的终止位置limit设置为当前位置（position）, ByteBuffer的position游标（当前位置）重设为0
        byteBuf.flip();
        length = storage.store(globalOffset, byteBuf);
        byteBuf.clear();
        globalOffset += length;
        offset = 0;
    }

    public void close() throws IOException {
        if (globalOffset < upperBound) {
            flush();
        }
    }
}
